package restful

import (
	"fmt"
	"moss/api"
	"moss/conf"
	"moss/proto"
	"moss/status"
	"net/http"
)

func AbortMultipartUploadHandler(w http.ResponseWriter, req *http.Request) {
	GeneralHandler(w, req, "AbortMultipartUploadHandler",
		func(w http.ResponseWriter, req *http.Request, requestId string) status.Status {
			rc := api.AbortMultipartUpload(getBucketName(req), getObjectName(req), getUploadId(req))
			if rc == status.Success {
				sendNoContent(requestId, w, nil)
			}
			return rc
		})
}

func ListMultipartUploadsHandler(w http.ResponseWriter, req *http.Request) {
	GeneralHandler(w, req, "ListMultipartUploadsHandler",
		func(w http.ResponseWriter, req *http.Request, requestId string) status.Status {
			delimiter := req.URL.Query().Get("delimiter")
			marker := req.URL.Query().Get("key-marker")
			prefix := req.URL.Query().Get("prefix")
			uploadIdMarker := req.URL.Query().Get("upload-id-marker")
			maxUploads := getQueryInt(req, "max-uploads", conf.Config.Limit.DefaultMaxKeys*10)

			xmlDoc, rc := api.ListMultipartUpload(requestId, getAccessKeyId(req), getBucketName(req),
				delimiter, marker, prefix, uploadIdMarker, maxUploads)

			if rc == status.Success {
				sendXmlDocument(xmlDoc, http.StatusOK, requestId, w, nil)
			}

			return rc
		})
}

func CompleteMultipartUploadHandler(w http.ResponseWriter, req *http.Request) {
	GeneralHandler(w, req, "CompleteMultipartUploadHandler",
		func(w http.ResponseWriter, req *http.Request, requestId string) status.Status {
			var cmu proto.CompleteMultipartUpload
			rc := loadAndValidateXmlDocument(&cmu, req)
			if rc != status.Success {
				return rc
			}

			uploadId := req.URL.Query().Get("uploadId")
			objectName := getObjectName(req)
			bucketName := getBucketName(req)

			xmlDoc, rc := api.CompleteMultipartUpload(requestId, getAccessKeyId(req), bucketName, objectName, uploadId, cmu.Part)

			if rc == status.Success {
				sendXmlDocument(xmlDoc, http.StatusOK, requestId, w, nil)
			}

			return rc
		})
}

func InitiateMultipartUploadHandler(w http.ResponseWriter, req *http.Request) {
	GeneralHandler(w, req, "InitiateMultipartUploadHandler",
		func(w http.ResponseWriter, req *http.Request, requestId string) status.Status {
			permission := getHeaderString(req, conf.HTTPHeaderOssACL, conf.PermissionObjectDefault)
			encryption := req.Header.Get(conf.HTTPHeaderOssServerSideEncryption)

			xmlDoc, rc := api.InitiateMultipartUpload(getAccessKeyId(req), getBucketName(req), getObjectName(req),
				permission, getUserMeta(req), encryption)

			if rc == status.Success {
				sendXmlDocument(xmlDoc, http.StatusOK, requestId, w, map[string]string{conf.HTTPHeaderOssServerSideEncryption: encryption})
			}

			return rc
		})
}

func UploadPartHandler(w http.ResponseWriter, req *http.Request) {
	GeneralHandler(w, req, "UploadPartHandler",
		func(w http.ResponseWriter, req *http.Request, requestId string) status.Status {
			partNumber := req.URL.Query().Get("partNumber")
			objectName := getObjectName(req)
			bucketName := getBucketName(req)
			uploadId := getUploadId(req)
			contentLength := req.ContentLength
			contentChecksum := req.Header.Get(conf.HTTPHeaderContentMD5)
			accessKeyId := getAccessKeyId(req)

			part, encryption, rc := api.UploadPart(requestId, accessKeyId, bucketName, objectName, partNumber, uploadId, req.Body, contentLength, contentChecksum)
			if rc == status.Success {
				sendSuccess(requestId, w, map[string]string{conf.HTTPHeaderEtag: part.ETag, conf.HTTPHeaderOssServerSideEncryption: encryption})
			}
			return rc
		})
}

func ListPartsHandler(w http.ResponseWriter, req *http.Request) {
	GeneralHandler(w, req, "ListPartsHandler",
		func(w http.ResponseWriter, req *http.Request, requestId string) status.Status {
			uploadId := req.URL.Query().Get("uploadId")
			objectName := getObjectName(req)
			bucketName := getBucketName(req)

			marker := req.URL.Query().Get("part-number-marker")
			maxParts := getQueryInt(req, "max-parts", conf.Config.Limit.DefaultMaxParts)

			xmlDoc, rc := api.ListParts(requestId, getAccessKeyId(req), uploadId, bucketName, objectName, marker, maxParts)
			if rc == status.Success {
				sendXmlDocument(xmlDoc, http.StatusOK, requestId, w, nil)
			}
			return rc
		})
}

func UploadPartCopyHandler(w http.ResponseWriter, req *http.Request) {
	GeneralHandler(w, req, "UploadPartCopyHandler",
		func(w http.ResponseWriter, req *http.Request, requestId string) status.Status {
			partNumber := req.URL.Query().Get("partNumber")
			objectName := getObjectName(req)
			bucketName := getBucketName(req)
			copyRange := req.Header.Get(conf.HTTPHeaderOssCopySourceRange)
			uploadId := req.URL.Query().Get("uploadId")

			contentChecksum := req.Header.Get(conf.HTTPHeaderContentMD5)
			accessKeyId := getAccessKeyId(req)

			encryption := req.Header.Get(conf.HTTPHeaderOssServerSideEncryption)
			if len(encryption) != 0 {
				return status.InvalidArgument
			}

			copySourceIfMatch := req.Header.Get(conf.HTTPHeaderOssCopySourceIfMatch)
			copySourceIfNoneMatch := req.Header.Get(conf.HTTPHeaderOssCopySourceIfNoneMatch)
			copySourceIfUnmodified := req.Header.Get(conf.HTTPHeaderOssCopySourceIfUnmodifiedSince)
			copySourceIfModified := req.Header.Get(conf.HTTPHeaderOssCopySourceIfModifiedSince)

			sourceBucket := getCopySourceBucketName(req)
			sourceObject := getCopySourceObjectName(req)
			srcObjectMeta, rc := api.GetObject(requestId, accessKeyId,
				sourceBucket, sourceObject,
				copySourceIfModified, copySourceIfUnmodified,
				copySourceIfMatch, copySourceIfNoneMatch)

			if rc != status.Success {
				return rc
			}

			hasRangeOption, startIdx, stopIdx := praseRangeString(copyRange)
			var contentRange string
			var length, offset int64
			if hasRangeOption {
				contentRange = fmt.Sprintf("bytes %d-%d/%d", startIdx, stopIdx, srcObjectMeta.Size)
				length = stopIdx + 1 - startIdx
				offset = startIdx
			} else {
				contentRange = ""
				length = srcObjectMeta.Size
				offset = 0
			}

			copyPartResult, rc := api.UploadPartCopy(requestId, accessKeyId, bucketName, objectName, partNumber, uploadId, srcObjectMeta, offset, length, contentChecksum)
			if rc == status.Success {
				sendXmlDocument(copyPartResult, http.StatusOK, requestId, w, map[string]string{conf.HTTPHeaderContentRange: contentRange})
			}
			return rc
		})
}
